#pragma once
#include "MyColor.h"
#include "MyVector3.h"
#include <vector>
#include "sgl.h"
#include "Context.h"
#include "MyMatrix.h"
#include "MyMaterial.h"
#include "MyPrimitive.h"
#include "MyTriangle.h";
#include "MySphere.h"
#include "MyPointLight.h"

class Context{

	public:

		//---------------------------------------------------------------------------
		// Transformation structures and variables
		//---------------------------------------------------------------------------
		//model & view matrix
		float * modelViewMatrix;
		// projection matrix
		float * projectionMatrix;
		//transformation matrix
		float * transformMatrix;
		//matrix, which is aplicated to vertex (multipl model*projection) 
		float * aplicMatrix;
		float * modelViewStack;
		int modelViewStackSize;

		//---------------------------------------------------------------------------
		// Variables to set
		//---------------------------------------------------------------------------
		bool drawing;
		MyColor currentColor;
		int width, height;
		float pointSize;
		int viewportX;
		int viewportY;
		int viewportWidth;
		int viewportHeight;
		sglEElementType elementType;
		sglEMatrixMode matrixMode;
		sglEAreaMode areaMode;
		
		//---------------------------------------------------------------------------
		// Z-buffer
		//---------------------------------------------------------------------------
		bool depth_test;
		float * z_buffer;

		//---------------------------------------------------------------------------
		// Data structures to drawing
		//---------------------------------------------------------------------------
		MyColor * colorBuffer;
		std::vector <MyVector3> vectorBuffer;
		
		//---------------------------------------------------------------------------
		// Data structures and variables to raytracing
		//---------------------------------------------------------------------------
		MyMaterial currentMaterial; 
		std::vector <MyPrimitive> primitiveBuffer;
		std::vector <MyPointLight> lightBuffer;
		bool sceneDefiniton;


		//---------------------------------------------------------------------------
		// Constructors, destructors
		//---------------------------------------------------------------------------
		Context(void){}
		~Context(void){}
		//set matrices, variables and viewport
		Context (int width, int height){
			this->drawing = false;
			this->depth_test = false;
			this->width = width;
			this->height = height;
			this->colorBuffer = new MyColor[width*height];
			this->z_buffer = new float[width*height];
			this->modelViewMatrix = new float[16];
			this->projectionMatrix = new float[16];
			this->transformMatrix = new float[16];
			this->aplicMatrix = new float[16];
			this->modelViewStack = new float[512];
			this->modelViewStackSize = 0;

			this->modelViewMatrix = MyMatrix::getIdentityMatrix();
			this->projectionMatrix = MyMatrix::getIdentityMatrix();
			this->transformMatrix = MyMatrix::getIdentityMatrix();
			this->aplicMatrix = MyMatrix::getNullMatrix();

			this->viewportHeight = height;
			this->viewportWidth = width;
			this->viewportX = 0;
			this->viewportY = 0;

			this->sceneDefiniton = false;
					
	}

		
		void setAplicMatrix();
		float * getColorBufferPointer();
		void clearTransformMatrix();
		void clearAplicMatrix();
		void end();
		void addSphere(float x, float y, float z, float radius);
		void addLight(float x, float y, float z, float r, float g, float b);
	
};

	std::vector <MyPrimitive> primitiveBuffer;
	bool sceneDefiniton;
	MyMaterial currentMaterial;
	int width, height;
	float pointSize;
	bool depth_test;
	bool drawing;

	float * modelViewMatrix;
	float * projectionMatrix;
	float * transformMatrix;
	float * aplicMatrix;
	MyColor * colorBuffer;
	float * z_buffer;
	MyColor currentColor;

	float viewportX;
	float viewportY;
	float viewportWidth;
	float viewportHeight;

	std::vector <MyVector3> vectorBuffer;
	sglEElementType elementType;
	sglEMatrixMode matrixmode;

	float * Context::getColorBufferPointer(){
		return &colorBuffer->r;
	}

	void Context::clearTransformMatrix(){
	
		this->transformMatrix = MyMatrix::getIdentityMatrix();
	}

	void Context::clearAplicMatrix(){
	
		this->aplicMatrix = MyMatrix::getNullMatrix();
		
	}

	//multip modelviewMatrix*projectionMatrix -> set aplicMatrix
	void Context::setAplicMatrix() {

		clearAplicMatrix();

		for(int i=0;i<4;i++){
			for(int j=0;j<4;j++){
				for (int inner = 0; inner < 4; inner++) {
					this->aplicMatrix[4 * i + j] +=  this->projectionMatrix[4 * i + inner]*this->modelViewMatrix[4 * inner + j]; 
				}
			}
		}

	}

	void Context::end(){
	
		if(this->sceneDefiniton){
		
			for(int i=0;i<this->vectorBuffer.size();i += 3){

				MyTriangle t(this->currentMaterial,vectorBuffer.at(i), vectorBuffer.at(i+1),vectorBuffer.at(i+2));
				this->primitiveBuffer.push_back(t);
			}
		}
	}

	void Context::addSphere(float x, float y, float z, float radius) {
		
		MySphere s(this->currentMaterial,x,y,z,radius);
		this->primitiveBuffer.push_back(s);
		
	}

	void Context::addLight(float x, float y, float z, float r, float g, float b) {
		
		MyPointLight l(x,y,z,r,g,b);
		this->lightBuffer.push_back(l);
		
	}
		
